// (C) 2021 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module lvds_mm
    #(
        parameter MASTER        =  1,
        parameter DATA_WIDTH    = 32,
        parameter ADDR_WIDTH    = 16,
        parameter TIMEOUT_PARAM = 25000
    ) 
(
    input                       clk,
    input                       reset,

    //Slave Agent interface, Only exist on master side
    input  [ADDR_WIDTH-1:0]     slv_agent_address,
    input                       slv_agent_read,
    input                       slv_agent_write,
    input  [DATA_WIDTH-1:0]     slv_agent_writedata,
    input  [(DATA_WIDTH/8)-1:0] slv_agent_byteenable,
    output [DATA_WIDTH-1:0]     slv_agent_readdata,
    output                      slv_agent_readdatavalid,
    output                      slv_agent_waitrequest,  

    //Master Agent interface, Only exist on slave side
    output [ADDR_WIDTH-1:0]     mstr_agent_address,
    output                      mstr_agent_read,
    output                      mstr_agent_write,
    output [DATA_WIDTH-1:0]     mstr_agent_writedata,
    output [(DATA_WIDTH/8)-1:0] mstr_agent_byteenable,
    input  [DATA_WIDTH-1:0]     mstr_agent_readdata,
    input                       mstr_agent_readdatavalid,
    input                       mstr_agent_waitrequest,
    
    //Encoding AVMM events to ioc frame
    output [7:0]                ioc_frame_o,
    input  [7:0]                ioc_frame_i,
    //tx/rx frame cnt
    input  [3:0]                tx_frm_offset,
    input  [3:0]                rx_frm_offset,
	 //input from channel_ctrl
	 input                       frame_loss_crc_A2H,
	 input                       frame_aligned_tx,
	 input                       frame_loss_crc_H2A,
    //Register outputs
    output [3:0]                status_reg,
	 output                      avmm_timeout,
    output                      crc_check_pass,      
    output                      unexpected_cmpl,    
    output [31:0]               timeout_cnt,          //Record how many timeout event has been happened
    output [31:0]               crc_err_cnt,          //Record how many crc_error has been happened
    output [31:0]               unexpected_cmpl_cnt,
	 input                       invalid_access_cpu,             //Only exist on agent side, input to MM SM         
    input                       invalid_access_dbg              //Only exist on agent side, input to MM SM

);

//mem intf between lvds_mm_slv.v & lvds_mm_ctrl
wire                  mem_slv_write_req;
wire                  mem_slv_read_req;
wire                  mem_slv_write_cmpl;
wire [ADDR_WIDTH-1:0] mem_slv_address;
wire [DATA_WIDTH-1:0] mem_slv_writedata;
wire [DATA_WIDTH-1:0] mem_slv_readdata;
wire                  mem_slv_readdatavalid;
//sb signals between lvds_mm_slv.v & lvds_mm_ctrl


//lvds_mm_slave ports only exist on ioc master side
generate 
    if ( MASTER == 1 )
    begin:gen_lvds_mm_slv_port

        lvds_mm_slave
            #(
                .DATA_WIDTH   ( DATA_WIDTH ),
                .ADDR_WIDTH   ( ADDR_WIDTH )
            )
        lvds_mm_slave_inst
        (
            .clk                     ( clk                       ),
            .reset                   ( reset                     ),
            //Slave Agent interface, Only exist on master side
            .slv_agent_address       ( slv_agent_address         ),
            .slv_agent_read          ( slv_agent_read            ),
            .slv_agent_write         ( slv_agent_write           ),
            .slv_agent_writedata     ( slv_agent_writedata       ),
            .slv_agent_byteenable    ( slv_agent_byteenable      ),
            .slv_agent_readdata      ( slv_agent_readdata        ),
            .slv_agent_readdatavalid ( slv_agent_readdatavalid   ),
            .slv_agent_waitrequest   ( slv_agent_waitrequest     ),
            //memory interface connected to lvds_mm_ctrl module
            .mem_write_req           ( mem_slv_write_req         ),
            .mem_read_req            ( mem_slv_read_req          ),
            .mem_write_cmpl          ( mem_slv_write_cmpl        ),
            .mem_address             ( mem_slv_address           ),
            .mem_writedata           ( mem_slv_writedata         ),
            .mem_readdata            ( mem_slv_readdata          ),
            .mem_readdatavalid       ( mem_slv_readdatavalid     ),
            //Sideband Signals connect to lvds_mm_ctrl module
			   .status_reg              ( status_reg                ),	
            .avmm_timeout            ( avmm_timeout              ),
            .crc_check_pass          ( crc_check_pass            ),
            .unexpected_cmpl         ( unexpected_cmpl           )
        );
        
    end else begin:gen_lvds_mm_mst_port
        assign slv_agent_readdata      = 'b0;
        assign slv_agent_readdatavalid = 'b0;
        assign slv_agent_waitrequest   = 'b0;
        assign mem_slv_write_req       = 'b0;
        assign mem_slv_read_req        = 'b0;
        assign mem_slv_address         = 'b0;
        assign mem_slv_writedata       = 'b0;
    end
endgenerate    

lvds_mm_ctrl
    #(
        .MASTER        (MASTER),
        .DATA_WIDTH    (DATA_WIDTH),
        .ADDR_WIDTH    (ADDR_WIDTH),
        .TIMEOUT_PARAM (TIMEOUT_PARAM)
    )
lvds_mm_ctrl_inst
(
    .clk                         ( clk                           ),
    .reset                       ( reset                         ),
    //memory interface, only exist on mcsi master side           
    .mem_slv_write_req           ( mem_slv_write_req             ),
    .mem_slv_read_req            ( mem_slv_read_req              ),    
    .mem_slv_write_cmpl          ( mem_slv_write_cmpl            ),   
    .mem_slv_address             ( mem_slv_address               ),
    .mem_slv_writedata           ( mem_slv_writedata             ),
    .mem_slv_readdata            ( mem_slv_readdata              ), 
    .mem_slv_readdatavalid       ( mem_slv_readdatavalid         ),
    //Master Agent interface, Only exist on slave side
    .mstr_agent_address          ( mstr_agent_address            ),
    .mstr_agent_read             ( mstr_agent_read               ),
    .mstr_agent_write            ( mstr_agent_write              ),
    .mstr_agent_writedata        ( mstr_agent_writedata          ),
    .mstr_agent_byteenable       ( mstr_agent_byteenable         ),
    .mstr_agent_readdata         ( mstr_agent_readdata           ),
    .mstr_agent_readdatavalid    ( mstr_agent_readdatavalid      ),
    .mstr_agent_waitrequest      ( mstr_agent_waitrequest        ),
    //input from lvds_channel_ctrl
	 .frame_loss_crc_A2H          ( frame_loss_crc_A2H            ),            
    .frame_aligned_tx            ( frame_aligned_tx              ),
    .frame_loss_crc_H2A          ( frame_loss_crc_H2A            ),	 
    //SB signals, only exist on master side
    .status_reg                  ( status_reg                    ),
	 .avmm_timeout                ( avmm_timeout                  ),
    .timeout_cnt                 ( timeout_cnt                   ),      
    .crc_check_pass              ( crc_check_pass                ),   
    .crc_err_cnt                 ( crc_err_cnt                   ),      
    .unexpected_cmpl             ( unexpected_cmpl               ),
    .unexpected_cmpl_cnt         ( unexpected_cmpl_cnt           ),
    //tx/rx frame cnt
    .tx_frm_offset               ( tx_frm_offset                 ),
    .rx_frm_offset               ( rx_frm_offset                 ),
    //Encoding AVMM events to ioc frame        
    .ioc_frame_o                 ( ioc_frame_o                   ),
    .ioc_frame_i                 ( ioc_frame_i                   ),
	 //IIC_MM access error report, only exist on mcsi agent side
	 .invalid_access_cpu          ( invalid_access_cpu            ), //Only exist on agent side, input to MM SM
    .invalid_access_dbg          ( invalid_access_dbg            )	//Only exist on agent side, input to MM SM 
);
    
endmodule    